package com.hr.config;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.interceptor.*;

import java.util.Collections;
import java.util.List;

/**
 * 事物配置
 */
//这是一个ioc容器配置类
@Configuration
//配置一个切面
@Aspect
//打开aop注解(一定要加上它,我们的aop注解才会生效)
@EnableAspectJAutoProxy
public class TxConfig {
    //spring 注入
    private DataSourceTransactionManager transactionManager;

    /**
     * 讲我们配置到的事务拦截器 注入到ioc容器
     * @return
     */
    @Bean
    public TransactionInterceptor advice(){
        //基于方法名匹配设置事物属性的类
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();

        //不打开事物的属性对象
        RuleBasedTransactionAttribute readOnly = new RuleBasedTransactionAttribute();
        //只读
        readOnly.setReadOnly(true);
        //事物的传播属性,PROPAGATION_NOT_SUPPORTED 表示不支持事物
        readOnly.setPropagationBehavior(TransactionAttribute.PROPAGATION_NOT_SUPPORTED);

        //get、query、select开头的方法不打开事物
        //TODO 如果你要改变不打开事物方法的规则名称，修改此处代码
        source.addTransactionalMethod("get*", readOnly);
        source.addTransactionalMethod("query*", readOnly);
        source.addTransactionalMethod("select*", readOnly);
        source.addTransactionalMethod("find*", readOnly);

        //打开事物的属性对象
        RuleBasedTransactionAttribute required = new RuleBasedTransactionAttribute();
        required.setReadOnly(false);
        //事物的传播属性,PROPAGATION_REQUIRED 支持当前事务，如果当前没有事务，就新建一个事务。这是最常见的选择
        required.setPropagationBehavior(TransactionAttribute.PROPAGATION_REQUIRED);
        //设置事物回滚规则, new RollbackRuleAttribute(Exception.class) 表示基于异常的回滚
        List<RollbackRuleAttribute> list = Collections.singletonList(new RollbackRuleAttribute(Exception.class));
        //规则是可以有很多的
        required.setRollbackRules(list);
        //其他方法都需要打开事物
        //TODO 如果你要改变打开事物规则的方法名称，修改此处代码
        source.addTransactionalMethod("*",required);

        //创建事物拦截器
        TransactionInterceptor interceptor = new TransactionInterceptor(transactionManager, source);
        return interceptor;
    }

    /**
     * 切入点相关配置对象
     * @param advice 注意,advice与上面的方法名称一致
     * @return
     */
    @Bean
    public Advisor advisor(TransactionInterceptor advice){
        //照顾事物的对象
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(advice);
        //事物的切入点
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        //切入service包中所有类中的方法
        //TODO 如果你要改变事物切入点的规则，修改此处代码
        pointcut.setExpression("execution(* com.hr.service.*.*(..))");
        //设置切入点
        advisor.setPointcut(pointcut);
        return advisor;
    }
}